package com.henu.acmrating.crawler;

import com.henu.acmrating.pojo.Problem;
import com.henu.acmrating.pojo.UserOj;
import com.henu.acmrating.service.ProblemService;
import com.henu.acmrating.service.UserOjService;
import com.henu.acmrating.utils.DateUtils;
import com.henu.acmrating.utils.StringUtils;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import us.codecraft.webmagic.Page;
import us.codecraft.webmagic.Site;
import us.codecraft.webmagic.Spider;
import us.codecraft.webmagic.processor.PageProcessor;
import us.codecraft.webmagic.selector.Html;
import us.codecraft.webmagic.selector.Selectable;

import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import java.util.List;

@Component
public class HDUProcessor implements PageProcessor {

    private static final String OJ_NAME = "HDU";
    private static final String BASE_URL = "http://acm.hdu.edu.cn/status.php?lang=0&status=0&user=";


    @Resource
    UserOjService userOjService;

    @Resource
    ProblemService problemService;

    public static HDUProcessor hduProcessor;

    @PostConstruct
    public void init() {
        hduProcessor = this;
    }

    @Override
    public void process(Page page) {
        Html html = page.getHtml();
        String account = StringUtils.getParam(page.getUrl().toString(), "user");
        List<Selectable> nodes = html.xpath("//div[@id=fixed_table]/table/tbody/tr[@align=center]").nodes();
        if(nodes.size() == 0) return ;
        // 1. 先拿到上一次爬取id
        UserOj userOj = hduProcessor.userOjService.selectByAccountAndOjName(account, OJ_NAME);
        int lastId = userOj.getLastId();

        int maxRunId = 0, nowRunId, solved = 0, submit = 0;
        // 标记是否继续爬虫下一页
        boolean flag = true;

        for (Selectable item : nodes) {
            Problem problem = new Problem(
                    userOj.getUserId(), OJ_NAME,
                    item.xpath("//tr/td[1]/allText()").toString(),
                    item.xpath("//tr/td[4]/allText()").toString(),
                    item.xpath("//tr/td[4]/a").links().toString(),
                    DateUtils.getDateByString(item.xpath("//tr/td[2]/allText()").toString()),
                    item.xpath("//tr/td[3]/allText()").toString(),
                    item.xpath("//tr/td[8]/allText()").toString(),
                    item.xpath("//tr/td[6]/allText()").toString(),
                    item.xpath("//tr/td[5]/allText()").toString()
            );
            // 结束爬虫 （没有数据的时候
            if(problem.getSubmitTime() == null) {
                flag = false;
                break;
            }
            nowRunId = Integer.parseInt(problem.getRunId());

            maxRunId = Math.max(maxRunId, nowRunId);
            if (nowRunId == lastId) {
                flag = false;
                break;
            }

            if(BaseProcessor.isContain(problem.getSubmitStatus())) {
                List<Problem> problems = hduProcessor.problemService.selectByUserIdAndProblemUrl(userOj.getUserId(), problem.getProblemUrl());
                if(problems.size() == 0) {
                    solved++;
                }
            }
            submit++;
            // 插入数据库
            hduProcessor.problemService.insert(problem);
        }

        // 更新 通过数
        userOj.setSolved(userOj.getSolved() + solved);
        userOj.setSubmissions(userOj.getSubmissions() + submit);
        if (maxRunId > userOj.getMaxId()) {
            userOj.setMaxId(maxRunId);
        }
        hduProcessor.userOjService.updateByPrimaryKeySelective(userOj);


        // 继续下一页
        if (flag) {
            String text = html.xpath("//div[@id=fixed_table]/p/a[3]/allText()").toString();
            if (text != null && text.contains("Next")) {
                String url = html.xpath("//div[@id=fixed_table]/p/a[3]").links().toString();
                if (url != null) {
                    page.addTargetRequest(url);
                }
            }

        }


    }

    private Site site = Site.me()
            .setTimeOut(15 * 1000)  // 设置超时时间
            .setRetrySleepTime(3000)// 设置重试的间隔时间
            .setRetryTimes(3);      // 设置重试次数

    @Override
    public Site getSite() {
        return site;
    }


//    @Scheduled(cron = "0 40 2 ? * * ")
    public void start() {
        Spider.create(new HDUProcessor())
                .addUrl(BaseProcessor.getUrls(userOjService, OJ_NAME, BASE_URL))
                .thread(1)
                .start();
    }

    public static void run_all() {
        Spider.create(new HDUProcessor())
                .addUrl(BaseProcessor.getUrls(hduProcessor.userOjService, OJ_NAME, BASE_URL))
                .thread(1)
                .start();
    }

    public static void run(String id) {
        Spider.create(new HDUProcessor())
                .addUrl(BASE_URL + id)
                .thread(1)
                .start();
    }

}
